import { Component, OnInit, ElementRef, Input, Output, EventEmitter,
  OnChanges, SimpleChanges } from '@angular/core';
import { FileInfo } from '../../models/fileinfo';
import { ElectronService } from '../../providers/electron.service';
import { BaseComponent } from '../base.component';
import { BeforeOpenFileEventArgs } from '../../models/eventargs';

/**文件元素id前缀 */
const FILE_PREFFIX = '_local_file_';

@Component({
  selector: 'app-filelist',
  templateUrl: './filelist.component.html',
  styleUrls: ['./filelist.component.scss']
})
export class FilelistComponent extends BaseComponent implements OnInit, OnChanges {
  //#region 属性定义
  /**文件集合 */
  files: FileInfo[];
  /**当前激活的文件或目录 */
  currentFocusItem: FileInfo;
  /**标识是否正在加载数据 */
  isLoading = true;
  /**异常信息 */
  exception: any;
  /**初始目录 */
  @Input() initDirectory: string;
  /**在根目录中发起向上层导航操作 */
  @Output() whenNavigateRoot = new EventEmitter();
  /**加载前处理事件 */
  @Output() whenBeforeEnumFiles = new EventEmitter();
  /**加载完成事件 */
  @Output() whenEnumFilesCompleted = new EventEmitter();
  /**
   * 打开文件前进行处理
   */
  @Output() whenBeforeOpenFile = new EventEmitter<BeforeOpenFileEventArgs>();
  /**当前目录信息 */
  private currentDirecory: string;
  /**之前目录信息 */
  private lastDir: string;
  //#endregion

  /**
   * 构造函数
   * @param electronService electron服务实例
   * @param el dom元素
   */
  constructor(electronService: ElectronService,
    el: ElementRef) {
      super(electronService, el);
    }

  ngOnInit() {
    this.enumDirectoryAndFiles(this.initDirectory);
  }
  ngOnChanges(changes: SimpleChanges) {
  }
  /**当前目录 */
  get curDirecory() {
    return this.currentDirecory;
  }
  /**
   * 按键事件处理
   * @param event 事件参数
   */
  onKeyup(event: KeyboardEvent) {
    const htmlElement = <HTMLElement>event.target;
    let tabIndex = htmlElement.tabIndex;
    const itemsLength = this.files ? this.files.length : 0;
    if (event.keyCode === 9) {
      // tab按键处理
      event.preventDefault();
      event.stopImmediatePropagation();
      // 切换tab键序
      if (event.target) {
        if (tabIndex === -1 && this.currentFocusItem) {
          tabIndex = this.files.indexOf(this.currentFocusItem);
        }
        tabIndex = tabIndex + 1 >= this.files.length ? 0 : tabIndex + 1;
        this.focusFileOrDirectoryByIndex(tabIndex);
      }
    } else if (((event.keyCode >= 65 && event.keyCode <= 90)
      || (event.keyCode >= 48 && event.keyCode <= 57)
      || (event.keyCode >= 96 && event.keyCode <= 105))
      && itemsLength > 0) {
      // a-z，0~1字母按键处理
      const key = event.key;
      const files: FileInfo[] = [];
      this.files.forEach(file => {
        if (file.fileName.toLowerCase().startsWith(key)) {
          files.push(file);
        }
      });
      if (files.length > 0) {
        if (this.currentFocusItem) {
          if (this.currentFocusItem.fileName.toLowerCase().startsWith(key)) {
            if (files.length > 1) {
              const index = files.indexOf(this.currentFocusItem);
              if (index + 1 <= files.length - 1) {
                this.focusFileOrDirectory(files[index + 1]);
                return;
              }
            } else {
              return;
            }
          }
        }
        this.focusFileOrDirectory(files[0]);
      }
    } else if (event.keyCode === 13) {
      // 回车按键处理
      event.preventDefault();
      event.stopImmediatePropagation();
      // 打开目录或文件
      this.openFileOrDirectory(this.currentFocusItem);
    } else if ((event.keyCode === 37 || event.keyCode === 39) && itemsLength > 0) {
      // 左、右箭头按键处理
      event.preventDefault();
      event.stopImmediatePropagation();
      // 设置当前文件索引
      let currentIndex = 0;
      currentIndex = this.files.indexOf(this.currentFocusItem);
      if (currentIndex >= 0) {
        if (event.keyCode === 37) {
          if (currentIndex - 1 >= 0) {
            currentIndex -= 1;
          }
        } else {
          if (currentIndex + 1 < itemsLength) {
            currentIndex += 1;
          }
        }
      }
      currentIndex = currentIndex < 0 ? 0 : currentIndex;
      // 使指定索引元素取得焦点
      this.focusFileOrDirectoryByIndex(currentIndex);
    } else if ((event.keyCode === 38 || event.keyCode === 40) && itemsLength > 0) {
      // 上、下箭头按键处理
      event.preventDefault();
      event.stopImmediatePropagation();
      //#region 计算每行显示的列数
      // 计算每行显示的列数
      let lastTop = 0, columnCount = 0;
      for (let index = 0; index < itemsLength; index++) {
        const id = `${FILE_PREFFIX}${index}`;
        const element: HTMLElement = this.getHtmlElementById(id);
        const rect = element.getBoundingClientRect();
        if (index === 0) {
          lastTop = rect.top;
        } else if (lastTop !== rect.top) {
          break;
        }
        columnCount++;
      }
      //#endregion

      // console.log(`itemsLength:${itemsLength},columnCount:${columnCount}`);

      //#region 计算当前移动到的元素索引
      // 计算当前移动到的元素索引
      let currentIndex = -1;
      currentIndex = this.files.indexOf(this.currentFocusItem);
      if (currentIndex >= 0) {
        if (event.keyCode === 38) {
          if (currentIndex - columnCount >= 0) {
            currentIndex -= columnCount;
          }
        } else {
          if (currentIndex + columnCount < itemsLength) {
            currentIndex += columnCount;
          }
        }
      }
      currentIndex = currentIndex < 0 ? 0 : currentIndex;
      //#endregion

      // 切换焦点
      this.focusFileOrDirectoryByIndex(currentIndex);
    } else if (event.keyCode === 8) {
      // backspace按键处理（返回上层）
      this.gotoLastLevel();
    }
  }
  /**
   * 返回上层
   */
  gotoLastLevel(): void {
    let dir: string = this.currentDirecory;
    if (dir.endsWith('\\')) {
      dir = dir.substring(0, dir.length - 1);
    }
    const pos = dir.lastIndexOf('\\');
    if (pos > -1) {
      dir = dir.substring(0, pos + 1);
      this.enumDirectoryAndFiles(dir);
    } else {
      if (this.whenNavigateRoot) {
        this.whenNavigateRoot.emit(this);
      }
    }
  }
  /**
   * 指定文件或目录获得焦点时进行的处理
   * @param file 待激活的文件信息
   */
  onFileOrDirectoryFocus(file: FileInfo) {
    this.currentFocusItem = file;
  }
  /**
   * 打开文件或目录
   * @param file 待打开的文件或目录
   */
  openFileOrDirectory(file: FileInfo) {
    if (file) {
      if (file.isDirectory) {
        // 枚举子目录
        this.enumDirectoryAndFiles(file.filePath);
      } else if (file.isFile) {
        if (this.whenBeforeOpenFile !== null) {
          const eventargs = new BeforeOpenFileEventArgs(file);
          this.whenBeforeOpenFile.emit(eventargs);
          if (eventargs.canceled) {
            return;
          }
        }
        // 打开文件
        this.electronService.openFile(file.filePath);
      }
    }
  }
  /**
   * 判断是否能返回上层
   */
  CheckCanGotoLastLevel(): boolean {
    return true;
  }
  /**使容器获得焦点 */
  focusContainer() {
    this.focusElementByClassName('file-container');
  }
  //#region 私有方法
  /**
   * 使页面上指定文件或目录元素获取到焦点
   * @param file 指定文件或目录信息
   */
  private focusFileOrDirectory(file: FileInfo) {
    const fIndex = this.files.indexOf(file);
    this.focusElement(`${FILE_PREFFIX}${fIndex}`);
  }
  /**
   * 使页面上指定索引的文件或目录元素获取到焦点
   * @param index 指定文件目录索引
   */
  private focusFileOrDirectoryByIndex(index: number) {
    this.focusElement(`${FILE_PREFFIX}${index}`);
  }
  /**
   * 枚举文件信息完成处理
   * @param error 错误信息
   * @param files 磁盘集合
   */
  private enumFilessCompleted(error: any, files: FileInfo[]) {
    this.files = files;
    this.exception = error;
    this.isLoading = false;
    if (this.whenEnumFilesCompleted) {
      this.whenEnumFilesCompleted.emit(this);
    }
    // 获取焦点
    this.focusContainer();
    // 设置指定的文件或目录元素为焦点元素
    if (this.files && this.files.length > 0 && this.lastDir) {
      const _lastDir = this.lastDir.endsWith('\\') ? this.lastDir : `${this.lastDir}\\`;
      for (let index = 0; index < this.files.length; index++) {
        const file = this.files[index];
        const filepath = file.filePath.endsWith('\\') ? file.filePath : `${file.filePath}\\`;
        if (filepath === _lastDir) {
          // 使当前的文件或目录对应的元素取得焦点
          this.executeAfterTimes(() => {
            this.focusFileOrDirectoryByIndex(index);
          }, 50);
          // 执行此段代码力求保险起见（放置interval触发是元素初始化未完成）
          this.onFileOrDirectoryFocus(file);
          break;
          }
      }
    }
  }
  /**
   * 枚举出指定目录下的所有目录和文件信息
   * @param dir 待检索的目录
   */
  private enumDirectoryAndFiles(dir: string): void {
    this.lastDir = this.currentDirecory;
    this.currentFocusItem = null;
    this.currentDirecory = dir;
    this.isLoading = true;
    this.exception = null;
    // 事件处理
    if (this.whenBeforeEnumFiles) {
      this.whenBeforeEnumFiles.emit(this);
    }
    // 枚举处理
    this.electronService.enumFiles(dir)
    .then(files => this.enumFilessCompleted(null, files))
    .catch((error) => this.enumFilessCompleted(error, null));
  }
  //#endregion
}
